package com.nxy.cpfsfe.facade;

import com.adtec.starring.datapool.CompSDO;
import com.adtec.starring.datapool.EPOper;
import com.adtec.starring.exception.BaseException;
import com.adtec.starring.struct.dta.DtaInfo;
import com.adtec.starring.util.SpringUtil;
import com.adtec.starring.util.StringTool;
import com.nxy.cpfsfe.cache.DbToParmToCache;
import com.nxy.cpfsfe.enumtype.*;
import com.nxy.cpfsfe.mybatis.mapper.*;
import com.nxy.cpfsfe.mybatis.pojo.*;
import com.nxy.cpfsfe.service.CpfsService;
import com.nxy.cpfsfe.util.*;
import org.apache.commons.lang3.StringUtils;
import org.apache.ibatis.session.SqlSession;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.slf4j.MDC;

import java.util.List;
import java.util.Map;


/**
 * 服务提供者
 */
public class Facade {

    //需要获取log4j中配置的 loggerName, 可以定义为常量
    public static final Logger LOGGER = LoggerFactory.getLogger(Facade.class);
    SqlSession sqlSession;
    public void server(String dir){
    	String initrSeqno="";
		String bizMsg=null;
        //《资源对象》定义
        try {
            //除了需要进行资源释放的代码全部写着try里面
            //日志MDC存放 initrSeqno(sdo head 中获取 initrSeqno值)， 《异步表达式》需要单独存放MDC
            String tpId = DtaInfo.getInstance().getTpId();
            CompSDO head = (CompSDO) EPOper.get(tpId, "ReqBean[0].head[0]");
            String sendAppCd = head.getSdoValue("sndAppCd").toString(); //请求方

            //以下两个字段 FE 主动调用 GW的时候返回
            String msgCode = head.getSdoValue("reqServCd").toString();//报文编号
            initrSeqno = head.getSdoValue("initrSeqno").toString(); //流水号

            MDC.put("seNo",initrSeqno);
            MDC.put("ROUTINGKEY" , LogUtil.getLogFileName(sendAppCd,msgCode));

			// 获取输入
			CompSDO inputSdo = (CompSDO) EPOper.getCompSDO(tpId, "ReqBody"); // 获取输入接口
			bizMsg = (String) inputSdo.getValue("BizMsg")!=null?(String) inputSdo.getValue("BizMsg"):"";

            //业务处理
            // 根据（请求方）+ （报文编号）决定使用什么业务处理
            String bizKey = "dispatcher/"+dir+sendAppCd+"-"+msgCode;
            //从参数表中获取调用的服务
            ToParm toParm = DbToParmToCache.toParmMap.get(bizKey);
            String serverName = "";
            if(toParm != null){
            	  serverName = toParm.getDataVal();
            }else {
                  EPOper.put(tpId, "RspBean[0].head[0].rspsCd", "90000");
                  EPOper.put(tpId, "RspBean[0].head[0].respsInfoDesc", bizKey+"服务没配置");
                  return;
			}
			//校验渠道日期
			if(dir.equals("A_")&&SysEcodeEnum.NPS.getCode().equals(msgCode.trim().substring(0,3))&&!SysEcodeEnum.NCS.getCode().equals(sendAppCd)){
				checkTime(dir,bizMsg,sendAppCd);
			}

            //权限检查
			checkPerm(dir,sendAppCd,msgCode);

            CpfsService service = (CpfsService) SpringUtil.getBean(serverName);
            long startTime = System.currentTimeMillis();
            service.doService();
            long endTime = System.currentTimeMillis();
            LOGGER.info("[{}] 服务耗时为:[{}] 毫秒", serverName, (endTime-startTime));

            //具体的服务里面返回RspBean的信息
        }catch(BaseException bizException){
            //业务异常处理
            String errorMsg = String.format("Facade模块调用异常，错误信息:%s,流水initrSeqno=[%s]",bizException.getErrorDesc(),initrSeqno);

            String tpId = DtaInfo.getInstance().getTpId();
            EPOper.put(tpId, "RspBean[0].head[0].rspsCd", bizException.getErrorCode());
            EPOper.put(tpId, "RspBean[0].head[0].respsInfoDesc", errorMsg);

            //异常日志记录
            LOGGER.error(errorMsg,bizException);

        } catch (Throwable e) {
            //未知异常日志记录
            String tpId = DtaInfo.getInstance().getTpId();
            EPOper.put(tpId, "RspBean[0].head[0].rspsCd", "90000");
            EPOper.put(tpId, "RspBean[0].head[0].respsInfoDesc", "未知异常,initrSeqno=["+initrSeqno+"]");
            LOGGER.error("发生未知异常,流水initrSeqno=["+initrSeqno+"]",e);
        } finally {
            try{
                MDC.clear();
                //资源对象释放
            }catch (Exception e){
                //异常日志记录
                String errorMsg = "释放MDC资源异常";
                LOGGER.error(errorMsg,e);
            }
        }
    }
    
    /**
     *权限检查方法
     * @param dir 同异步方式
     * @param sendAppCd 发起系统编号
     * @param msgCode  报文编号
     */
    public void checkPerm(String dir, String sendAppCd, String msgCode) {
    	String tpId = DtaInfo.getInstance().getTpId();		
		// 获取输入
		CompSDO inputSdo = (CompSDO) EPOper.getCompSDO(tpId, "ReqBody"); // 获取输入接口		
		String bizMsg = (String) inputSdo.getValue("BizMsg");
		if(StringUtils.isBlank(sendAppCd)){
			throw new BaseException(RespCd.NCPO0110,"报文体缺少sedAppCd属性");
		}
		if(StringUtils.isBlank(bizMsg)){
			throw new BaseException(RespCd.NCPO0110,"报文体缺少BizMsg属性");
		}
		if(StringUtils.isBlank(msgCode)){
			throw new BaseException(RespCd.NCPO0110,"报文体缺少报文编号reqServCd属性");
		}
		String orgNo="";
		try {
			if(SysEcodeEnum.NCS.getCode().equals(sendAppCd)){
				//来账不检查权限
	            return;
			}else {
	            orgNo = XmlUtil.getValByXPath(bizMsg,"/transaction/header/msg/sndMbrCd");
	            //CPFS报文处理
				orgNo = StringTool.isNullOrEmpty(orgNo) ? XmlUtil.getValByXPath(bizMsg,"/root/MsgHeader/SndBankId"):orgNo;
				if(orgNo.length()<12){
					orgNo =	getBankNo(orgNo,sendAppCd);
				}
				LOGGER.debug("发起行行号[{}]",orgNo);
	        }
		} catch (Exception e) {
			throw new BaseException(RespCd.NCPO5400,"发起行行号"+orgNo);
		}		
        ToParm checkPer = DbToParmToCache.toParmMap.get("transPermission/checkPermission");
        //查询发起系统是否开通权限
		try {
			if(checkPer == null){
				LOGGER.debug("系统参数表to_parm的transPermission/checkPermission开通权限参数未配置，默认不检查交易权限");
				return;
			}
			if(checkPer != null && StatEnum.PERMISSION_CHECK_Y.getCode().equals(checkPer.getDataVal())){
				if(queryToBizSysPerm(sendAppCd)){
					ToBizTyp toBizTyp = queryToBizTypPerm(msgCode);
					//toBizTyp查到且开通状态是“0-未开通”的权限检查不通过，其余为权限检查通过
					if(toBizTyp != null && StatEnum.OPEN_PERMISSION_Y.getCode().equals(toBizTyp.getOpenFlg())){
						if(queryTrSysBizTypPerm(orgNo,sendAppCd,msgCode)){
							return;
						}
					}else if(toBizTyp==null){
						return;
					}
				}
			}else {
                LOGGER.debug("不检查交易权限");
                return;
            }
		} catch (Exception e) {
			throw new BaseException(RespCd.NCPO5400,e,orgNo+"权限检查异常");	
		}       
		//权限检查不通过时执行下面操作
        if(dir.equals("")){
    		LOGGER.debug("同步权限检查拒绝信息");
			throw new BaseException(RespCd.NCPO5400,"系统:["+sendAppCd+"],行号：["+orgNo+"],报文类型：["+msgCode+"]权限未开通");
        }else if(dir.equals("A_") && !SysEcodeEnum.CPFS.getCode().equals(msgCode.substring(0,4))){//异步处理权限检查CPFS报文不发911
    		LOGGER.debug("异步权限检查拒绝信息911拒绝报文");
    		Map bizMap = xml2BizMap(bizMsg,sendAppCd,msgCode,orgNo);
    		returnGWNPS911(bizMap,sendAppCd);
			throw new BaseException(RespCd.NCPO5400,"系统:["+sendAppCd+"],行号：["+orgNo+"],报文类型：["+msgCode+"]权限未开通");
    	}      
	}
    
    
    public boolean queryToBizSysPerm(String sendAppCd) {
    	boolean bool = false;
    	sqlSession = (SqlSession) SpringUtil.getBean("mybatisSqlSession");
		ToBizSysMapper toBizSysMapper = sqlSession.getMapper(ToBizSysMapper.class);
		ToBizSys toBizSysReturn = toBizSysMapper.queryBizSysIsEnb(sendAppCd);
		if(toBizSysReturn!=null){
			 bool = true;
		}
    	
    	return bool;
    }

    /**
	 *检查报文发送时间和支付通道时间是否一致
	 */
	public void checkTime(String dir,String bizMsg,String sendAppCd){
	    String msgId =  XmlUtil.getValByXPath(bizMsg,"//MsgId");
		String msgTime = msgId.substring(0,8);
		ToPChl toPChl = ToPChlUtil.getInstance().getToPChlByPcId(SysEcodeEnum.NCS.getCode());
        LOGGER.info("MsgId日期[{}],NCS通道日期[{}]",msgTime,DateUtil.date4Str(toPChl.getpCD()));
        if(msgTime.equals(DateUtil.date4Str(toPChl.getpCD()))){
		    return;
		}else{
			LOGGER.info("报文日期与支付通道NCS的pCD日期不一致,MsgId日期[{}],NCS通道日期[{}]",msgTime,DateUtil.date4Str(toPChl.getpCD()));
			Map<String, String> map = XmlUtil.xml2Map(bizMsg);
			map.put("OrgnlMsgId",msgId);
			map.put("PrcDt",DateUtil.date3Str(toPChl.getpCD()));
			map.put("OrgnlTranChnlTyp",XmlUtil.getValByXPath(bizMsg,"//TranChnlTyp"));
			returnGWNPS900(map,sendAppCd);
			throw new BaseException(RespCd.NCPO6653,"报文日期与支付通道NCS的pCD时间不一致");

		}

	}
	/**
	 * 查到且开通状态是“0-未开通”的权限检查不通过，其余为权限检查通过
	 */
	public ToBizTyp queryToBizTypPerm(String msgCode) {
		sqlSession = (SqlSession) SpringUtil.getBean("mybatisSqlSession");
		ToBizTypMapper toBizTypMapper = sqlSession.getMapper(ToBizTypMapper.class);
		ToBizTyp toBizTypReturn = toBizTypMapper.queryBizSysTypByBizClsId(msgCode);
		return toBizTypReturn;
	}	
	
	public boolean queryTrSysBizTypPerm(String orgNo, String sendAppCd, String msgCode) {
		boolean bool = false;	
		TrSysBizTyp tsbt = new TrSysBizTyp();
		tsbt.setBizSysId(sendAppCd);
		tsbt.setOrgId(orgNo);
		tsbt.setBizClsId(msgCode);
		sqlSession = (SqlSession) SpringUtil.getBean("mybatisSqlSession");
		TrSysBizTypMapper trSysBizTypMapper = sqlSession.getMapper(TrSysBizTypMapper.class);
		TrSysBizTyp trSysBizTypReturn = trSysBizTypMapper.queryOpenStatByOrgId(tsbt);
	    if(trSysBizTypReturn!=null &&StatEnum.OPEN_PERMISSION_Y.getCode().equals(trSysBizTypReturn.getOpenFlg())){
	    	 bool = true;				 
	    }
	    return bool;
	}

	public String returnGWNPS900(Map<String, String> bizmap,String sndAppCd){
		String tpId = DtaInfo.getInstance().getTpId();
		String rspCd = "";
		try {
			String bizMsg900 = ResponseUtil.build900Xml(bizmap);
			//转发给网关
			LOGGER.debug("rpc调用网关发送NPS900开始......");
			EPOper.put(tpId, "ReqBean[0].head[0].sndAppCd", sndAppCd);
			EPOper.put(tpId, "ReqBean[0].head[0].rcvAppCd", sndAppCd);
			EPOper.put(tpId, "ReqBean[0].head[0].reqServCd", MsgCdOrTpEnum.MSGCD_900.getCode());
			//EPOper.put(tpId, "ReqBean[0].head[0].initrSeqno",bizmap.get("seqNb"));
			EPOper.getCompSDO(tpId, "ReqBody").setValue("BizMsg", bizMsg900);
			rspCd = RpcCommUtil.getInstance().rpcFeToGW(tpId, RpcOutputInfoEnum.OutputName_Pub_Cpfsgw.getCode(),RpcOutputInfoEnum.OutPutSvr_CpfsFwdThrdPrtS.getCode());
		} catch (Exception e) {
			rspCd = RespCd.NCPO6047;
			String seqNb = (String)bizmap.get("/transaction/header/msg/seqNb")!=null?(String)bizmap.get("/transaction/header/msg/seqNb"):"";
			LOGGER.error("900权限拒绝报文发送异常,msgId=["+seqNb+"]",e);
		}
		return rspCd;
	}
  
	public String returnGWNPS911(Map<String, String> bizmap,String sndAppCd){
		String tpId = DtaInfo.getInstance().getTpId();	
		String rspCd = "";
		try {
			String bizMsg911 = ResponseUtil.build911Xml(bizmap);		
			//转发给网关
		    LOGGER.debug("rpc调用网关发送NPS911开始......");
		    EPOper.put(tpId, "ReqBean[0].head[0].sndAppCd", sndAppCd);
		    EPOper.put(tpId, "ReqBean[0].head[0].rcvAppCd", sndAppCd);
	    	EPOper.put(tpId, "ReqBean[0].head[0].reqServCd", MsgCdOrTpEnum.MSGCD_911.getCode());
	    	//EPOper.put(tpId, "ReqBean[0].head[0].initrSeqno",bizmap.get("seqNb"));
		    EPOper.getCompSDO(tpId, "ReqBody").setValue("BizMsg", bizMsg911);   
		    rspCd = RpcCommUtil.getInstance().rpcFeToGW(tpId, RpcOutputInfoEnum.OutputName_Pub_Cpfsgw.getCode(),RpcOutputInfoEnum.OutPutSvr_CpfsFwdThrdPrtS.getCode());	
		} catch (Exception e) {
			rspCd = RespCd.NCPO6047;
			String msgId = (String)bizmap.get("/transaction/header/msg/seqNb")!=null?(String)bizmap.get("/transaction/header/msg/seqNb"):"";
			LOGGER.error("911权限拒绝报文发送异常,msgId=["+msgId+"]",e);
		}
		return rspCd;
	}
	
	/**
	 * 解析报文并做特殊处理
	 * @param bizMsg
	 * @param sndAppCd
	 * @return
	 */
	public Map xml2BizMap (String bizMsg,String sndAppCd,String msgCode,String orgNo){
		
		Map xml2BizMap = XmlUtil.xml2Map(bizMsg);
		Map<String, Object> map = xml2BizMap;	
		String rsMsg = String.format("交易[%s]未授权给[%s] [%s]", msgCode,sndAppCd,orgNo);
		map.put("PrcCd","ESBO0110");
		map.put("RjctInf",rsMsg);
		LOGGER.info("权限检查不通过返回map为：[{}]" , map.toString());
		return map;
		
	}


	public String getBankNo(String sndBankId,String sendAppCd) {
		String orgBNo = sndBankId;
		sqlSession = (SqlSession) SpringUtil.getBean("mybatisSqlSession");
		if (BnknoCdEnum.BNKNOCD_0000.getCode().equals(sndBankId)) {
			ToParmMapper toParmMapper = sqlSession.getMapper(ToParmMapper.class);
			ToParm toParm = new ToParm();
			toParm.setDataCd(sendAppCd);
			toParm.setDataTyp(DataTypeEnum.BIZSYS.getCode());
			List<ToParm> list = toParmMapper.query(toParm);
			if (list != null&&list.size()>0) {
				if (list.size() == 1) {
					orgBNo = list.get(0).getDataVal();
				} else {
					throw new BaseException(RespCd.NCPO0007, "参数信息表数据异常" + sndBankId);
				}
			} else {
				throw new BaseException(RespCd.NCPO0007, "发送行不正确：" + sndBankId + ",或参数信息表未定义");

			}
		} else {
			ToOrgMapper toOrgMapper = sqlSession.getMapper(ToOrgMapper.class);
			ToOrg toOrg = new ToOrg();
			toOrg.setOrgId(sndBankId);
			toOrg.setOrgCls("1");
			List<ToOrg> list = toOrgMapper.query(toOrg);
			if (list != null&&list.size()>0) {
				if (list.size() == 1) {
					orgBNo = list.get(0).getOrgBNo();
				} else {
					throw new BaseException(RespCd.NCPO0007, "机构信息表数据不唯一" + sndBankId);
				}
			} else {
				throw new BaseException(RespCd.NCPO0007, "发送行不正确：" + sndBankId + ",或机构信息表未定义");

			}
		}
			return orgBNo;
	}

}
